from commonrules import CommonRules
from Mastergoal.Common.team import Team
from Mastergoal.Common.square import Square
from level2rules import L2Rules
from Mastergoal.Common.piece import *

class L3Rules(L2Rules):
    
    @staticmethod
    def correct_player_move(state, move):
        """ Extends basic players moves for level three """
        
        col_before = move.piece.square.col
        row_after = move.piece.square.row
        col_after = move.square.col
        row_after = move.square.row
        
        b = state.board
        p = move.piece
        
        if not L2Rules.correct_player_move(state, move):
            return False
        
        # Check goal-keeper move
        if p.id == PlayerPiece.G and b.big_area(p.orientation, col_after, row_after):
            if ( 
            CommonRules.occupied(state, col, row) 
            and not (col_before == col_after-1 and row_before == row_after)  
            and b.big_area(p.orientation, col_after - 1, row_after) 
            and (b.ballpiece.square.col != col_after-1 or b.ballpiece.square.row != row_after)
            ):
                return False
            
        # A player can't stand next to a goal-keeper
        else:
            for k in b.get_keepers():
                if (
                    b.big_area(k.orientation, col_after, row_after)
                    and b.big_area(k.orientation, k.square.col, k.square.row)
                    and row_after == k.square.row
                    and (col_after + 1 == k.square.col or col_after - 1 == k.square.col)
                ):
                    return False
        
        return True
    
    @staticmethod
    def neutral_square(state, ball_square):
        
        if not L2Rules.neutral_square(state, ball_square):
            return False
        
        for keeper in state.board.get_keepers():
            if keeper.square.row == ball_square.row \
                and (keeper.square.col+1 == ball_square.col or keeper.square.col-1 == ball_square.col) \
                and state.board.big_area(keeper.orientation, keeper.col, keeper.row) \
                and state.board.big_area(keeper.orientation, ball_square.col, ball_square.row):
                    return False
        
        return True
    
    @staticmethod
    def is_goalkeeper(state, orientation, square):
        
        """ Checks if square is being occupied by keeper """
        
        keeper = state.board[orientation].get_keeper()
        if keeper.square.row == square.row:
            if state.board.big_area(orientation, square.col, square.row):
                # keeper occupies big area
                if keeper.square.col == col:
                    return 1
                # keeper's arms occupies big area
                if ((keeper.square.col+1 == square.col or keeper.square.col-1 == square.col) 
                    and state.board.big_area(orientation, keeper.square.col, keeper.square.row)):
                    return 2
        
        return False
    
    @staticmethod
    def valid_ball_move(state, move, cls):
        """ Verifies validity of ball move in level three """
        
        col_before = move.piece.square.col
        row_before = move.piece.square.row
        col_after = move.square.col
        row_after = move.square.row
        
        # Check level one and two rules
        response = L2Rules.valid_ball_move(state, move, cls)
        if not response[0]:
            return response
        
        # Player moving the ball
        player = move.player_moving
        
        # response[1] contains information about True response from L2
        if response[1] == CommonRules.VALID_NEUTRAL:
            # Special square overrides neutral square
            if state.board.special_square(player.orientation, col_after, row_after):
                return (True, CommonRules.VALID_NEUTRAL_REPEAT)
            
            return (True, CommonRules.VALID_NEUTRAL)
        
        elif response[1] == CommonRules.VALID_PASS or L3Rules.is_goalkeeper(state, player.orientation, move.square) == 2:
              return (True, CommonRules.VALID_PASS)
          
        # Special square
        if state.board.special_square(player.orientation, col_after, row_after):
            return (True, CommonRules.VALID_REPEAT_TURN) 
        
        # GOAL-KEEPER Rules
        opponent_team = (player.orientation == Team.UP and Team.UP or Team.DOWN)
        op_keeper = state.board[opponent_team].get_keeper()
        # Player can't pass ball to opponent keeper (it may appear neutral square but it's not when keeper is in possession)
        if op_keeper.square.row == move.square.row \
            and (op_keeper.square.col+1 == move.square.col or op_keeper.square.col-1 == move.square.col) \
            and state.board.big_area(op_keeper.orientation, op_keeper.square.col, op_keeper.square.row) \
            and state.board.big_area(op_keeper.orientation, col_after, row_after):
                return (False, CommonRules.INVALID_PASS_OPPONENT)
        
        # Ball moves up or down in a straight line
        if col_before == col_after:
            # Ball moves down
            if row_before < row_after:
                for row in range(row_before+1, row_after):
                    
                    if state.board.opponent_in_square(player, col_after, row) and state.board.little_area(op_keeper.orientation, col_after, row):     
                        return (False, CommonRules.INVALID_LITTLE_AREA_DEFENSE)
                    
                    if L3Rules.is_goalkeeper(state, op_keeper.orientation, Square(col_after,row)) != 0:
                        return (False, CommonRules.INVALID_OVER_KEEPER)
                
                    if L3Rules.is_goalkeeper(state, op_keeper.orientation, Square(col_after,row)) == 1 or \
                        L3Rules.is_goalkeeper(state, player.orientation, Square(col_after,row)) == 1:
                        return (False, CommonRules.INVALID_OVER_KEEPER)
            # Ball moves up        
            else:
                for row in range(row_before-1, row_after, -1):
                    if state.board.opponent_in_square(player, col_after, row) and state.board.little_area(op_keeper.orientation, col_after, row):     
                        return (False, CommonRules.INVALID_LITTLE_AREA_DEFENSE)
                    
                    if L3Rules.is_goalkeeper(state, op_keeper.orientation, Square(col_after,row)) != 0:
                        return (False, CommonRules.INVALID_OVER_KEEPER)
                
                    if L3Rules.is_goalkeeper(state, op_keeper.orientation, Square(col_after,row)) == 1 or \
                        L3Rules.is_goalkeeper(state, player.orientation, Square(col_after,row)) == 1:
                        return (False, CommonRules.INVALID_OVER_KEEPER)
        
        # Ball moves in a straight line from the sides
        elif row_before == row_after: 
            # Ball moves down
            if col_before < col_after:
                for col in range(col_before+1, col_after):
                    if state.board.opponent_in_square(player, col_after, row) and state.board.little_area(op_keeper.orientation, col_after, row):     
                        return (False, CommonRules.INVALID_LITTLE_AREA_DEFENSE)
                    
                    if L3Rules.is_goalkeeper(state, op_keeper.orientation, Square(col_after,row)) != 0:
                        return (False, CommonRules.INVALID_OVER_KEEPER)
                
                    if L3Rules.is_goalkeeper(state, op_keeper.orientation, Square(col_after,row)) == 1 or \
                        L3Rules.is_goalkeeper(state, player.orientation, Square(col_after,row)) == 1:
                        return (False, CommonRules.INVALID_OVER_KEEPER)
            # Ball moves up
            else:
                for col in range(col_before-1, col_after, -1):
                    if state.board.opponent_in_square(player, col_after, row) and state.board.little_area(op_keeper.orientation, col_after, row):     
                        return (False, CommonRules.INVALID_LITTLE_AREA_DEFENSE)
                    
                    if L3Rules.is_goalkeeper(state, op_keeper.orientation, Square(col_after,row)) != 0:
                        return (False, CommonRules.INVALID_OVER_KEEPER)
                
                    if L3Rules.is_goalkeeper(state, op_keeper.orientation, Square(col_after,row)) == 1 or \
                        L3Rules.is_goalkeeper(state, player.orientation, Square(col_after,row)) == 1:
                        return (False, CommonRules.INVALID_OVER_KEEPER)
        
        # Ball moves in a diagonal
        else:
            # moves up
            if col_before > col_after:
                # moves up from right side
                if row_before < row_after: 
                    col = col_before - 1
                    for row in range(row_before+1, row_after):
                        if state.board.opponent_in_square(player, col, row) and state.board.little_area(op_keeper.orientation, col, row):     
                            return (False, CommonRules.INVALID_LITTLE_AREA_DEFENSE)
                    
                        if L3Rules.is_goalkeeper(state, op_keeper.orientation, Square(col,row)) != 0:
                            return (False, CommonRules.INVALID_OVER_KEEPER)
                    
                        if L3Rules.is_goalkeeper(state, op_keeper.orientation, Square(col,row)) == 1 or \
                            L3Rules.is_goalkeeper(state, player.orientation, Square(col,row)) == 1:
                            return (False, CommonRules.INVALID_OVER_KEEPER)   
                        col -= 1
                # moves up from left side
                else:
                    col = col_before - 1
                    for row in range(row_before-1, row_after, -1):
                        if state.board.opponent_in_square(player, col, row) and state.board.little_area(op_keeper.orientation, col, row):     
                            return (False, CommonRules.INVALID_LITTLE_AREA_DEFENSE)
                    
                        if L3Rules.is_goalkeeper(state, op_keeper.orientation, Square(col,row)) != 0:
                            return (False, CommonRules.INVALID_OVER_KEEPER)
                    
                        if L3Rules.is_goalkeeper(state, op_keeper.orientation, Square(col,row)) == 1 or \
                            L3Rules.is_goalkeeper(state, player.orientation, Square(col,row)) == 1:
                            return (False, CommonRules.INVALID_OVER_KEEPER)   
                        col -= 1
            # moves down in a diagonal
            else:
                # moves down from right side
                if row_before < row_after:
                    col = col_before + 1
                    for row in range(row_before+1, row_after):
                        if state.board.opponent_in_square(player, col, row) and state.board.little_area(op_keeper.orientation, col, row):     
                            return (False, CommonRules.INVALID_LITTLE_AREA_DEFENSE)
                    
                        if L3Rules.is_goalkeeper(state, op_keeper.orientation, Square(col,row)) != 0:
                            return (False, CommonRules.INVALID_OVER_KEEPER)
                    
                        if L3Rules.is_goalkeeper(state, op_keeper.orientation, Square(col,row)) == 1 or \
                            L3Rules.is_goalkeeper(state, player.orientation, Square(col,row)) == 1:
                            return (False, CommonRules.INVALID_OVER_KEEPER)   
                        col += 1  
                # moves down from left side
                else: 
                    col = col_before + 1
                    for row in range(row_before-1, row_after, -1):
                        if state.board.opponent_in_square(player, col, row) and state.board.little_area(op_keeper.orientation, col, row):     
                            return (False, CommonRules.INVALID_LITTLE_AREA_DEFENSE)
                    
                        if L3Rules.is_goalkeeper(state, op_keeper.orientation, Square(col,row)) != 0:
                            return (False, CommonRules.INVALID_OVER_KEEPER)
                    
                        if L3Rules.is_goalkeeper(state, op_keeper.orientation, Square(col,row)) == 1 or \
                            L3Rules.is_goalkeeper(state, player.orientation, Square(col,row)) == 1:
                            return (False, CommonRules.INVALID_OVER_KEEPER)   
                        col += 1  
        return response
    
    
    
    
    